home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
parse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
31KB
|
1,292 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mutt_regex.h"
#include "mailbox.h"
#include "mime.h"
#include "parse.h"
#include "rfc2047.h"
#ifdef _PGPPATH
#include "pgp.h"
#endif /* _PGPPATH */
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <stdlib.h>
/* Reads an arbitrarily long header field, and looks ahead for continuation
* lines. ``line'' is dynamically increased if more space is required to fit
* the whole line.
*/
char *mutt_read_rfc822_line (FILE *f, char *line, size_t *linelen)
{
size_t offset = 0, l;
char buf[LONG_STRING];
char ch, *pbuf, *q;
int is_cont = 0; /* continuation line? */
int is_full;
if (line)
*line = 0;
FOREVER
{
if (fgets (buf, sizeof (buf), f) == NULL)
return (line);
/* check to see if we got a full line */
l = strlen (buf);
is_full = (!l || buf[l - 1] == '\n');
pbuf = buf;
if (is_cont)
{
/* unfold the continuation line, as described by MIME */
for (; ISSPACE (*pbuf); pbuf++, l--) /* empty */
;
if (*pbuf)
{
*--pbuf = ' '; /* convert to a single space */
l++;
}
}
is_cont = 0;
/* if we got a full line, remove trailing space */
if (l && pbuf[l - 1] == '\n')
{
for (q = pbuf + l - 1 ; q >= pbuf && ISSPACE (*q) ; q--, l--)
*q = 0;
}
if (offset + l > *linelen)
{
/* not enough space to hold the (rest of the) line, grow the buffer */
if (line)
{
*linelen = offset + l;
safe_realloc ((void **) &line, *linelen + 1);
}
else
{
*linelen = l;
line = safe_malloc (*linelen + 1);
}
}
else if (!l && !line)
{
/* Avoid a segfault if the first line we read is blank. */
return (NULL);
}
if (l)
{
memcpy (line + offset, pbuf, l + 1);
offset += l;
}
/* check to see if we got a full line */
if (!is_full)
continue; /* no, read the next part */
/* a blank line indicates the end of the message header */
if (! *line)
return (line);
/* check to see if the next line is a continuation line */
ch = fgetc (f);
ungetc (ch, f);
if (ch != ' ' && ch != '\t')
return (line); /* next line is a separate header field or EOH */
is_cont = 1;
}
/* not reached */
}
static LIST *mutt_parse_references (char *s)
{
LIST *t, *lst = NULL;
while ((s = strtok (s, " \t")) != NULL)
{
/*
* some mail clients add other garbage besides message-ids, so do a quick
* check to make sure this looks like a valid message-id
*/
if (*s == '<')
{
t = (LIST *)safe_malloc (sizeof (LIST));
t->data = safe_strdup (s);
t->next = lst;
lst = t;
}
s = NULL;
}
return (lst);
}
int mutt_check_encoding (const char *c)
{
if (strncasecmp ("7bit", c, sizeof ("7bit")-1) == 0)
return (ENC7BIT);
else if (strncasecmp ("8bit", c, sizeof ("8bit")-1) == 0)
return (ENC8BIT);
else if (strncasecmp ("binary", c, sizeof ("binary")-1) == 0)
return (ENCBINARY);
else if (strncasecmp ("quoted-printable", c, sizeof ("quoted-printable")-1) == 0)
return (ENCQUOTEDPRINTABLE);
else if (strncasecmp ("base64", c, sizeof("base64")-1) == 0)
return (ENCBASE64);
else
return (ENCOTHER);
}
static PARAMETER *parse_parameters (const char *s)
{
PARAMETER *head = 0, *cur = 0, *new;
char buffer[LONG_STRING];
const char *p;
size_t i;
while (*s)
{
if ((p = strpbrk (s, "=;")) == NULL)
{
dprint(1, (debugfile, "parse_parameters: malformed parameter: %s\n", s));
return (head); /* just bail out now */
}
/* if we hit a ; now the parameter has no value, just skip it */
if (*p != ';')
{
i = p - s;
new = mutt_new_parameter ();
new->attribute = safe_malloc (i + 1);
memcpy (new->attribute, s, i);
new->attribute[i] = 0;
/* remove whitespace from the end of the attribute name */
while (ISSPACE (new->attribute[--i]))
new->attribute[i] = 0;
s = p + 1; /* skip over the = */
SKIPWS (s);
if (*s == '"')
{
s++;
for (i=0; *s && *s != '"' && i < sizeof (buffer) - 1; i++, s++)
{
if (*s == '\\')
{
/* Quote the next character */
buffer[i] = s[1];
if (!*++s)
break;
}
else
buffer[i] = *s;
}
buffer[i] = 0;
if (*s)
s++; /* skip over the " */
}
else
{
for (i=0; *s && *s != ' ' && *s != ';' && i < sizeof (buffer) - 1; i++, s++)
buffer[i] = *s;
buffer[i] = 0;
}
new->value = safe_strdup (buffer);
/* Add this parameter to the list */
if (head)
{
cur->next = new;
cur = cur->next;
}
else
head = cur = new;
}
else
{
dprint (1, (debugfile, "parse_parameters(): parameter with no value: %s\n", s));
s = p;
}
/* Find the next parameter */
if (*s != ';' && (s = strchr (s, ';')) == NULL)
break; /* no more parameters */
do
{
s++;
/* Move past any leading whitespace */
SKIPWS (s);
}
while (*s == ';'); /* skip empty parameters */
}
return (head);
}
int mutt_check_mime_type (const char *s)
{
if (strcasecmp ("text", s) == 0)
return TYPETEXT;
else if (strcasecmp ("multipart", s) == 0)
return TYPEMULTIPART;
else if (strcasecmp ("application", s) == 0)
return TYPEAPPLICATION;
else if (strcasecmp ("message", s) == 0)
return TYPEMESSAGE;
else if (strcasecmp ("image", s) == 0)
return TYPEIMAGE;
else if (strcasecmp ("audio", s) == 0)
return TYPEAUDIO;
else if (strcasecmp ("video", s) == 0)
return TYPEVIDEO;
else
return TYPEOTHER;
}
static void parse_content_type (char *s, BODY *ct)
{
char *pc;
char buffer[SHORT_STRING];
short i = 0;
safe_free((void **)&ct->subtype);
mutt_free_parameter(&ct->parameter);
/* First extract any existing parameters */
if ((pc = strchr(s, ';')) != NULL)
{
*pc++ = 0;
while (*pc && ISSPACE (*pc))
pc++;
ct->parameter = parse_parameters(pc);
/* Some pre-RFC1521 gateways still use the "name=filename" convention */
if ((pc = mutt_get_parameter("name", ct->parameter)) != 0)
ct->filename = safe_strdup(pc);
}
/* Now get the subtype */
if ((pc = strchr(s, '/')))
{
*pc++ = 0;
while (*pc && !ISSPACE (*pc) && *pc != ';')
{
buffer[i++] = *pc;
pc++;
}
buffer[i] = 0;
ct->subtype = safe_strdup (buffer);
}
/* Finally, get the major type */
ct->type = mutt_check_mime_type (s);
if (ct->subtype == NULL)
{
/* Some older non-MIME mailers (i.e., mailtool, elm) have a content-type
* field, so we can attempt to convert the type to BODY here.
*/
if (ct->type == TYPETEXT)
ct->subtype = safe_strdup ("plain");
else if (ct->type == TYPEAUDIO)
ct->subtype = safe_strdup ("basic");
else if (ct->type == TYPEMESSAGE)
ct->subtype = safe_strdup ("rfc822");
else if (ct->type == TYPEOTHER)
{
ct->type = TYPEAPPLICATION;
snprintf (buffer, sizeof (buffer), "x-%s", s);
ct->subtype = safe_strdup (buffer);
}
else
ct->subtype = safe_strdup ("x-unknown");
}
}
static void parse_content_disposition (char *s, BODY *ct)
{
PARAMETER *parms;
if (!strncasecmp ("inline", s, 6))
ct->disposition = DISPINLINE;
else if (!strncasecmp ("form-dat